﻿/*
 *GreyBox was written by Strategic Data Systems and licenced under the open source MS-PL. 
 */
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using StrategicDataSystems.Cloud.Monitoring.Configuration;
using StrategicDataSystems.Cloud.Monitoring.HostedServices;
using StrategicDataSystems.Cloud.Monitoring.UI.Services;

namespace StrategicDataSystems.Cloud.Monitoring.UI.ViewModels
{
    public class SysTrayViewModel : ViewModelBase
    {
        private INotificationService _notificationService;
        private ITimerService _refreshTimerService;
        private IHostedServiceManagement _hostedServiceGateway;
        private Settings _settings;
        private ObservableCollection<HostedService> _hostedServices = new ObservableCollection<HostedService>();
        private ICommand _exitCommand;
        private ICommand _refreshCommand;
        private ICommand _killAllDeploymentsCommand;
        private ICommand _killDeploymentCommand;
        private INetPresenceService _netPresenceService;


        /// <summary>
        /// Initializes a new instance of the SysTrayViewModel class.
        /// </summary>
        /// <param name="timerService"></param>
        /// <param name="hostedServices"></param>
        public SysTrayViewModel(
            IHostedServiceManagement hostedServiceGateway,
            Settings settings,
            INotificationService notificationService,
            ITimerService timerService,
            INetPresenceService netPresenceService)
        {
            _hostedServiceGateway = hostedServiceGateway;
            _settings = settings;
            _notificationService = notificationService;
            _refreshTimerService = timerService;
            _netPresenceService = netPresenceService;
            refreshHostedServices();
            notifyUserOfAnyDeployments();
            setupRefreshTimer();
        }

        public ICommand ExitCommand
        {
            get
            {
                if (_exitCommand == null)
                {
                    _exitCommand = new RelayCommand(param => this.ExitApplication());
                }
                return _exitCommand;
            }
        }

        public ICommand RefreshCommand
        {
            get
            {
                if (_refreshCommand == null)
                {
                    _refreshCommand = new RelayCommand(param => this.manualRefreshDeploymentList());
                }
                return _refreshCommand;
            }
        }

        public ICommand KillDeploymentCommand
        {
            get
            {
                if (_killDeploymentCommand == null)
                {
                    _killDeploymentCommand = new RelayCommand(param => this.killSingleDeployment(param));
                }
                return _killDeploymentCommand;
            }
        }

        public ICommand KillAllDeploymentsCommand
        {
            get
            {
                if (_killAllDeploymentsCommand == null)
                {
                    _killAllDeploymentsCommand = new RelayCommand(param => this.killAllDeployments(), param => this.SubscriptionHasCurrentDeployments);
                }
                return _killAllDeploymentsCommand;
            }
        }

        public bool InternetConnectionIsAvailable
        {
            get
            {
                return _netPresenceService.InternetConnectionIsAvailable();
            }
        }

        private void ExitApplication()
        {
            Trace.WriteLine("Exit was called by the user.");
            Application.Current.Shutdown(0);
        }


        private void killSingleDeployment(object deploymentToKill)
        {
            Trace.WriteLine("Kill Single Deployment called.", "UserInteraction");
            if (_netPresenceService.InternetConnectionIsAvailable())
            {
                if (deploymentToKill is Deployment)
                {
                    Deployment deployment = (Deployment)deploymentToKill;
                    _notificationService.NotifyUserOfKillCommand(1);
                    BackgroundWorker worker = new BackgroundWorker();
                    worker.DoWork += delegate(object sender, DoWorkEventArgs e)
                    {
                        killDeployment(deployment);
                    };
                    worker.RunWorkerAsync();
                }
            }
            else
            {
                _notificationService.NotifyUserOfLostConnection();
                refreshHostedServices();
            }

        }

        private void manualRefreshDeploymentList()
        {
            Trace.WriteLine("Refresh called.", "UserInteraction");
            if (_netPresenceService.InternetConnectionIsAvailable())
            {
                try
                {
                    this._refreshTimerService.Pause();
                    checkForDeploymentsInTheBackground();
                }
                finally
                {
                    this._refreshTimerService.Resume();
                }
            }
            else
            {
                _notificationService.NotifyUserOfLostConnection();
                refreshHostedServices();
            }
        }

        private void killAllDeployments()
        {
            Trace.WriteLine("Kill All Deployments called.", "UserInteraction");
            if (_netPresenceService.InternetConnectionIsAvailable())
            {
                IEnumerable<Deployment> activeDeployments = ActiveDeployments;
                if (activeDeployments.Any())
                {
                    BackgroundWorker worker = new BackgroundWorker();
                    _notificationService.NotifyUserOfKillCommand(activeDeployments.Count());
                    worker.DoWork += delegate(object sender, DoWorkEventArgs e)
                                     {
                                         foreach (Deployment deployment in activeDeployments)
                                         {
                                             killDeployment(deployment);
                                         }
                                     };
                    worker.RunWorkerAsync();
                }
            }
            else
            {
                _notificationService.NotifyUserOfLostConnection();
                refreshHostedServices();
            }
        }

        private void killDeployment(Deployment deployment)
        {
            _hostedServiceGateway.KillHostedServiceDeployment(_settings.SubscriptionId,
                                                            _settings.CertificateThumbprint,
                                                            deployment.HostedServiceName,
                                                            deployment.Slot);
        }

        public ObservableCollection<HostedService> HostedServices
        {
            get
            {
                return _hostedServices;
            }
        }

        public ObservableCollection<Deployment> ActiveDeployments
        {
            get
            {
                var activeDeployments = from hostedService in _hostedServices
                                        where hostedService.Deployments.Count() > 0
                                        from deployment in hostedService.Deployments
                                        select deployment;
                return new ObservableCollection<Deployment>(activeDeployments);
            }
        }

        private bool _subscriptionHasCurrentDeployments;
        public bool SubscriptionHasCurrentDeployments
        {
            get { return _subscriptionHasCurrentDeployments; }
            private set
            {
                if (_subscriptionHasCurrentDeployments == value)
                {
                    return;
                }
                _subscriptionHasCurrentDeployments = value;
                base.OnPropertyChanged("SubscriptionHasCurrentDeployments");
            }
        }

        private void refreshHostedServices()
        {
            if (_netPresenceService.InternetConnectionIsAvailable())
            {
                string subscriptionId = _settings.SubscriptionId;
                string certificateThumbprint = _settings.CertificateThumbprint;
                _hostedServices = new ObservableCollection<HostedService>(
                    _hostedServiceGateway.GetHostedServicesForSubscription(subscriptionId, certificateThumbprint));
            }
            else
            {
                _hostedServices = new ObservableCollection<HostedService>();
            }
            base.OnPropertyChanged("HostedServices");
            base.OnPropertyChanged("ActiveDeployments");
            base.OnPropertyChanged("SubscriptionHasCurrentDeployments");
            base.OnPropertyChanged("InternetConnectionIsAvailable");
        }

        private void notifyUserOfAnyDeployments()
        {
            IEnumerable<Deployment> activeDeployments = ActiveDeployments;

            if (activeDeployments.Any())
            {
                SubscriptionHasCurrentDeployments = true;
                _notificationService.NotifyUserOfActiveDeployment(activeDeployments.Count());
            }
            else
            {
                SubscriptionHasCurrentDeployments = false;
            }
            Trace.WriteLine(string.Format("Greybox found {0} deployments for the subscription.", activeDeployments.Count()));
        }

        private void setupRefreshTimer()
        {
            _refreshTimerService.Start(_settings.RefreshTimerIntervalInMinutes, this.refreshTimer_Ellapsed);
        }

        void refreshTimer_Ellapsed(object sender, EventArgs args)
        {
            Trace.WriteLine("Refresh timer elapsed.  Refresh hosted services and notify.", "System");
            checkForDeploymentsInTheBackground();
        }

        private void checkForDeploymentsInTheBackground()
        {
            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += delegate(object s, DoWorkEventArgs e)
            {
                refreshHostedServices();
            };
            worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs e)
            {
                if (e.Error != null)
                {
                    Trace.TraceError(e.Error.ToString());
                }
                else
                {
                    notifyUserOfAnyDeployments();
                }
            };
            worker.RunWorkerAsync();
        }
    }
}
